﻿//
// $HeadURL: http://codeka-memcache.googlecode.com/svn/trunk/Codeka.Memcache/Commands/GetCommand.cs $
// $Revision: 11 $
// $Author: dean.codeka $     $Date: 2010-02-21 08:02:52 +0000 (Sun, 21 Feb 2010) $
//
// Copyright © 2009-2010 Dean Harding, all rights reserved.
//

using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace Codeka.Memcache.Commands
{
    /// <summary>
    /// The "Get" command fetches a value from the cache.
    /// </summary>
    public class GetCommand : Command
    {
        private List<string> keys;
        private List<object> values;
        private List<long> casValues;

        /// <summary>
        /// Constructs a new <see cref="GetCommand"/> with the given keys.
        /// </summary>
        public GetCommand(params string[] keys)
        {
            this.keys = new List<string>(keys);
            this.values = new List<object>(keys.Length);
            this.casValues = new List<long>(keys.Length);
        }

        /// <summary>
        /// Gets the <see cref="ICollection{T}"/> of keys we sent to the server.
        /// </summary>
        public ICollection<string> Keys { get { return keys; } }

        /// <summary>
        /// Gets the <see cref="ICollection{T}"/> of values we got back from the server.
        /// </summary>
        public ICollection<object> Values { get { return values; } }

        /// <summary>
        /// Gets the <see cref="ICollection{T}"/> of check-and-set values we got back
        /// from the server.
        /// </summary>
        public ICollection<long> CasValues { get { return casValues; } }

        /// <summary>
        /// Get an <see cref="IEnumerable{T}"/> collection of <see cref="Packet"/>s that
        /// we want to send to the server.
        /// </summary>
        public override IEnumerable<Packet> GetPackets()
        {
            for(int i = 0; i < keys.Count; i++)
            {
                yield return new Packet {
                    Header = {
                                PacketType = PacketType.Request,
                                OpCode = (i == keys.Count - 1) ? PacketOpCode.GetWithKey : PacketOpCode.GetWithKeyQuiet,
                            },
                        Key = keys[i],
                    };
            }
        }

        /// <summary>
        /// This is called when we get a response from the server.
        /// </summary>
        public override bool ProcessResponse(Packet pkt)
        {
            int index = keys.IndexOf(pkt.Key);

            if (pkt.Header.StatusCode == StatusCodes.NoError && index >= 0)
            {
                while (values.Count <= index)
                    values.Add(null);
                while (casValues.Count <= index)
                    casValues.Add(0);

                values[index] = DeserializeValue(pkt.Value);
                casValues[index] = pkt.Header.CasValue;
            }

            return (index != keys.Count - 1);
        }

        /// <summary>
        /// Serializes the given value into a byte array, for storage.
        /// </summary>
        private object DeserializeValue(byte[] value)
        {
            // todo: make this pluggable
            var fmt = new BinaryFormatter();
            var ms = new MemoryStream(value);
            return fmt.Deserialize(ms);
        }
    }
}
